#include "../global/global_declarations.h"
#include "stdlib.h"
#include "string.h"
#include "ctype.h"
#include "stdio.h"
#include "../global/misc.h"
#include "../DEHT/deht.h"
#include "assert.h"
#include "../global/global_auth.h"

/**
 * checks whether the arguments given in the command line are in the right form.
 */
bool check_argv(int n, char* argv[]) {
	if (n != 2) {
		fprintf(stderr,
				"Error: Usage salty_authenticate <authentication table text file>\n");
		return false;
	}
	return check_file(argv[1]);
}

/**
 * erases the last 6 bytes (48 bits) of the arr.
 * @precondition: dest must be longer than 6 bytes.
 */
void cut_last_6_bytes(char* dest) {
	int i, l;
	l = strlen(dest);
	if (l < 6)
		return;
	for (i = 1; i <= 6; ++i) {
		dest[l - i] = 0;
	}
}

/**
 * return the matching password to the given key in the file.
 * return -1 if the key is not in the file.
 */
int get_salty_password(char* key, FILE* f, char* dest) {
	if (get_value(key, f, dest, '\t') == -1)
		return -1;
	else
		cut_last_6_bytes(dest);
	return 0;
}

/**
 * returns the matching salt to the key in the file.
 * @precondition: the key must be in the file.
 * @precondition: salt must be at least 7 bytes long.
 */
void get_salt(char* key, FILE* f, unsigned char* salt) {
	int l;
	char temp[MAX_LINE_LENGTH] = { 0 };
	get_value(key, f, temp, '\t');
	l = strlen(temp);
	memcpy(salt, temp + l - 6, 6);
}

/**
 * match the key to the password in the file.
 */
bool match(char* key, char* value, FILE* f, BasicHashFunctionPtr func,
		int hash_length) {
	unsigned char salt[7] = { 0 };
	char pass[MAX_LINE_LENGTH] = { 0 };
	char hashed_value[MAX_LINE_LENGTH] = { 0 };
	if (get_salty_password(key, f, pass) == -1)
		return -1;
	get_salt(key, f, salt);
	get_salty_hexadecimal_hashed_password(value, salt, func, hash_length,
			hashed_value);
	return (strcmp(hashed_value, pass) == 0);
}

/**
 *
 */
bool process_line(char* com_line, FILE* f, BasicHashFunctionPtr func,
		int hash_length) {
	char* value;
	bool matching_state;
	char key[MAX_LINE_LENGTH] = {0};
	get_word_num(com_line, 1, key, '\t');
	value = get_word_num_ptr(com_line, 2, '\t');
	matching_state = match(key, value, f, func, hash_length);;
	if (matching_state == -1) {
		printf("Denied\n");
		return -1;
	}
	if (matching_state) {
		printf("Approved\n");
		return true;
	}
	printf("Denied\n");
	return false;
}

int main(int argc, char* argv[]) {
	int hash_length;
	FILE* f;
	BasicHashFunctionPtr func;
	char com_line[MAX_LINE_LENGTH];
	char hash_name[20] = {0};
	if (!check_argv(argc, argv))
		return 6;
	f = fopen(argv[1], "r");
	get_hash_name_from_file(f, hash_name);
	func = which_hash(hash_name);
	hash_length = hash_Length(hash_name);
	while (true) {
		printf(">>");
		fgets(com_line, MAX_LINE_LENGTH, stdin);
		remove_end_of_line(com_line);
		if (strcmp(com_line, "quit") == 0)
			break;
		if (strcmp(com_line, "") == 0)
			continue;
		if (count_words_in_line(com_line, '\t') != 2)
			fprintf(stderr,
					"Error: Commands are either “quit” or <user name>tab<password>.\n");
		else
			process_line(com_line, f, func, hash_length);
		memset(com_line, 0, MAX_LINE_LENGTH);
	}
	fclose(f);
	return 0;
}
